﻿using EmbeddedSensorCloud.HTTP;
using System;
using System.Text;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;

namespace EmbeddedSensorCloud.Plugin.Temperature
{
    public sealed class Program : IPlugin
    {
        private enum RequestType
        {
            Error,
            Standard,
            REST,
            Search,
            Page
        }

        private readonly ResponseCreator _Creator;
        private readonly Timer _CollectSensorData;

        #region Constructor/Init

        public Program(string server, string database, string tableName, string uid, string password)
        {
            this._Creator = new ResponseCreator(server, database, tableName, uid, password);
            this._Creator.OnTimerException += Creator_OnTimerException;

            this._CollectSensorData = new Timer(this._Creator.WriteSensorDataToDB);
        }

        public void Initialize()
        {
            this._CollectSensorData.Change(Timeout.Infinite, 2000);
        }

        #endregion

        #region IPlugin Interface

        public bool IsResponseable(Request request)
        {
            return request.Url.StartsWith("/GetTemperature", true, CultureInfo.InvariantCulture);
        }

        public Response Respond(Request request)
        {
            Response responseToClient = new Response();

            string responseHTML = Properties.Resources.ResourceManager.GetString("index");
            string failMessage = "<h2>Wrong Temperature-URL</h2>";
            string numberOfPages = "Pages: " + this._Creator.GetPageNumbers();
            
            switch (CheckURL(request.Url, request.Args))
            {
                case RequestType.Standard:
                    //string retVal = string.Join(System.Environment.NewLine, System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames());
                    responseHTML = responseHTML.Replace("@@data@@", this._Creator.GetDataOfPage("0"));
                    responseHTML = responseHTML.Replace("@@pages@@", numberOfPages);
                    break;
                case RequestType.REST:
                    responseHTML = this._Creator.CreateRESTDocument(request.Url);
                    responseToClient.Headers["Content-Type"] = "text/xml; charset=utf-8";
                    break;
                case RequestType.Search:
                    responseHTML = responseHTML.Replace("@@data@@", this._Creator.GetDataAtDate(request.Args["search"]));
                    responseHTML = responseHTML.Replace("@@pages@@", string.Empty);
                    break;
                case RequestType.Page:
                    responseHTML = responseHTML.Replace("@@data@@", this._Creator.GetDataOfPage(request.Args["page"]));
                    responseHTML = responseHTML.Replace("@@pages@@", numberOfPages);
                    break;
                default:
                    responseHTML = failMessage;
                    break;
            }
            responseToClient.Body = Encoding.UTF8.GetBytes(responseHTML);

            return responseToClient;
        }

        #endregion

        #region CheckURL

        /// <summary>
        /// Checks the URL and its arguments to see what kind of request was made.
        /// </summary>
        /// <param name="url">The URL part after the hostname and the port.</param>
        /// <param name="args">A Dictionary with both its types set to string.</param>
        /// <returns>An enum with represents the found request type.</returns>
        private RequestType CheckURL(string url, Dictionary<string, string> args)
        {
            string[] urlParts = url.Split(new char[] { '/' }, 2, StringSplitOptions.RemoveEmptyEntries);

            if (urlParts.Length < 1 || urlParts.Length > 2 || (urlParts.Length >= 1 && urlParts[0].ToLowerInvariant() != "gettemperature"))
            { return RequestType.Error; }

            if (urlParts.Length == 2)
            {
                if (Regex.IsMatch(urlParts[1], @"^[0-9]{4}(/[0-9]{2}){0,2}$", RegexOptions.CultureInvariant))
                { return RequestType.REST; }
            }
            else
            {
                switch (args.Count)
                {
                    case 0:
                        return RequestType.Standard;
                    case 1:
                        if (args.ContainsKey("search"))
                        {
                            if (Regex.IsMatch(args["search"], @"^([0-9]{2}\.){2}[0-9]{4}$", RegexOptions.CultureInvariant))
                            { return RequestType.Search; }
                        }
                        else if (args.ContainsKey("page"))
                        {
                            int test;
                            if (int.TryParse(args["page"], out test))
                            { return RequestType.Page; }
                        }
                        break;
                    default:
                        break;
                }
            }
            return RequestType.Error;
        }

        #endregion

        private void Creator_OnTimerException(object sender, Exception e)
        {
            this._CollectSensorData.Change(Timeout.Infinite, 0);
            //throw (e);
        }
    }
}